package terracraft.blocs;

import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import terracraft.GameError;

/**
 * Cette classe représente tout bloc dans le jeu.
 * 
 * @author linkpy
 */
public abstract class Bloc {
    // +------------------------------------------------------+
    // |    Champs public static                              |
    // +------------------------------------------------------+
    
    /** Nombre maximal de blocs dans le jeu. */
    public static final int BLOC_MAX = 4096;
    /** Largeur d'un bloc fois deux ( image ). */
    public static final int LARGEUR = 16;
    /** Hauteur d'un bloc fois deux ( image ). */
    public static final int HAUTEUR = LARGEUR;
    
    // +------------------------------------------------------+
    // |    Champs private/protected static                   |
    // +------------------------------------------------------+
    
    /** Liste des blocs. */
    private static Bloc[] Blocs = new Bloc[BLOC_MAX];
    
    // La liste des bloc est ici : sinon il y a un exception !
    public static final Bloc air = new BlocAir("Air", 0);
    public static final Bloc terre = new BlocTerre("Terre", 1);
    public static final Bloc herbe = new BlocHerbe("Herbe", 2);
    
    // +------------------------------------------------------+
    // |    Champs public                                     |
    // +------------------------------------------------------+
    
    // Aucun champs 
    
    // +------------------------------------------------------+
    // |    Champs private                                    |
    // +------------------------------------------------------+
    
    /** Est-ce-que le bloc a été enregisté dans la liste ? */
    private boolean enregistre;
    
    /** Nom du bloc. */
    private String nom;
    /** ID du bloc. ( position dans la liste ) */
    private int id;
    
    // +------------------------------------------------------+
    // |    Champs protected                                  |
    // +------------------------------------------------------+
    
    /** Image du bloc. */
    protected Image image;
    
    // +------------------------------------------------------+
    // |    Méthodes public static                            |
    // +------------------------------------------------------+
    
    /*
     * Dans les fonction en-dessous, si le bloc n'est pas trouvé, elles 
     * renvoient le bloc d'air ( qui a pour ID 0, pour nom "Air" ).
     */
    
    /**
     * Récupère le bloc avec son ID.
     * 
     * @param id L'ID ( position dans le tableau ) du bloc
     * @return Le bloc. Attention : le bloc peut être null ! 
     */
    public static Bloc avoirBlocAvecID(int id) {
        if(id < 0 || id > BLOC_MAX - 1)
            return Blocs[0];
        
        return Blocs[id];
    }
    
    /**
     * Récupère l'ID du bloc avec son nom.
     * 
     * @param nom Le nom du bloc
     * @return L'ID du bloc.
     */
    public static int avoirBlocIDAvecNom(String nom) {
        for(int i = 0; i < BLOC_MAX; i++) {
            String n = Blocs[i].avoirNom();
            if(nom.equals(n))
                return i;
        }
        
        return 0;
    }
    
    /**
     * Récupère le bloc avec son nom.
     * 
     * Est égale à avoirBlocAvecID(avoirBlocIDAvecNom(nom)).
     * 
     * @param nom Le nom du bloc
     * @return Le bloc
     */
    public static Bloc avoirBlocAvecNom(String nom) {
        return avoirBlocAvecID(avoirBlocIDAvecNom(nom));
    }
    
    // +------------------------------------------------------+
    // |    Méthodes private/protected static                 |
    // +------------------------------------------------------+
    
    // Aucune méthodes
    
    // +------------------------------------------------------+
    // |    Constructeur public                               |
    // +------------------------------------------------------+
    
    // Aucun constructeur
    
    // +------------------------------------------------------+
    // |    Constructeur private/protected                    |
    // +------------------------------------------------------+
    
    protected Bloc(String nom, int id) {
        this.nom = nom;
        this.id = id;
        
        enregistre = false;
        image = null;
        
        chargeImage();
        enregister();
    }
    
    // +------------------------------------------------------+
    // |    Méthodes public                                   |
    // +------------------------------------------------------+
    
    /**
     * Enregistre le bloc dans la liste des blocs.
     */
    public void enregister() {
        if(enregistre)
            throw new GameError("Bloc.enregister", "Impossible d'enregistré un"
                    +"bloc plus d'une fois.");
        
        Bloc b = Blocs[id];
        if(b != null) {
            String bn = b.avoirNom();
            
            throw new GameError("Bloc.enregister", "L'emplacement du bloc "+id+
                    " est déja utilisé. Nom : "+nom+"->"+bn);
        }
        
        Blocs[id] = this;
        enregistre = true;
    }
    
    /**
     * Récupère le nom du bloc.
     * 
     * @return Le nom du bloc
     */
    public String avoirNom() {
        return nom;
    }
    
    /**
     * Récupère l'ID du bloc.
     * 
     * @return L'ID du bloc
     */
    public int avoirID() {
        return id;
    }
    
    
    /**
     * Affiche l'image du bloc en X, Y en utilisant l'afficheur G.
     * 
     * L'afficheur G n'est là que si on a besoin de faire des effet sur 
     * l'affichage du bloc ( rotation, redimantionnement, effet, etc... )
     * 
     * Grâce a l'utilisation de l'afficheur, on peut affiché l'image sur une
     * image.
     * 
     * @param x Position X où l'image sera affiché
     * @param y Position Y où l'image sera affiché
     * @param g Afficheur utilisé.
     */
    public void afficher(int x, int y, Graphics g) {
        if(image != null) {
            g.scale(2, 2);
            g.drawImage(image, x, y);
        }
    }
    
    /**
     * Renvois si le bloc doit être mit à jour.
     * 
     * Exemple : le bloc d'herbe renvois true : pour que l'herbe pousse sur les
     * bloc de terre qui son à coté.
     * 
     * @return 
     */
    public boolean doitEtreMisAJour() {
        return false;
    }
    
    // +------------------------------------------------------+
    // |    Méthodes abstract                                 |
    // +------------------------------------------------------+
    
    /**
     * Méthode appelé par le constructeur pour chargé l'image.
     */
    protected abstract void chargeImage();
    
    /**
     * Met à jour le bloc.
     * 
     * Si la méthodes doitEtreMisAJour renvois true, cette méthode est appelé.
     */
    public abstract void misAJour();
}
